package net.yvesd.cellhunter;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.yvesd.cellhunter.model.Cell;
import net.yvesd.cellhunter.model.coverage.CellCoverage;
import net.yvesd.cellhunter.model.coverage.MapCoverage;
import net.yvesd.cellhunter.model.coverage.SignalStrengthLocation;
import net.yvesd.cellhunter.persistance.CellHunterDbOpenHelper;
import net.yvesd.cellhunter.persistance.CopyFile;
import android.app.Dialog;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

public class MainActivity extends MapActivity {

	private MapView mapView;
	private MyLocationOverlay myLocationOverlay;
	private List<Overlay> overlays;
	private LocationManager locationManager;
	private TelephonyManager tm;
	private MapCoverage mapCoverage;
	private StrengthListener strengthListener;
	private int currentLac;
	private int currentCid;

	// Overlays
	private Drawable drawable;
	private CellItemizedOverlay itemizedOverlay;
	private MyLocationListener myLocationListener;
	private boolean itemizedOverlayAlreadyAdded;

	private final int SELECT_CELL_RESULTCODE = 0;
	private final int EDIT_CELL_RESULTCODE = 1;
	private final int DELETE_CELL_RESULTCODE = 2;

	// Dialogs
	static final int DIALOG_EDIT_CELL = 0;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);

		Toast.makeText(this, getString(R.string.app_welcomeText),
				Toast.LENGTH_SHORT).show();

		// find components by id
		mapView = (MapView) findViewById(R.id.mapview);

		// Maps
		mapView.setBuiltInZoomControls(true);
		myLocationOverlay = new MyLocationOverlay(this, mapView);
		overlays = mapView.getOverlays();
		overlays.add(myLocationOverlay);

		// Get system services
		locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
		tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

		// Map coverage
		mapCoverage = new MapCoverage(getApplicationContext());

		// Overlays
		drawable = getResources().getDrawable(R.drawable.cell);
		itemizedOverlay = new CellItemizedOverlay(drawable, getResources());

		// reload from database
		reloadFromDB();

		// Listeners
		strengthListener = new StrengthListener();
		myLocationListener = new MyLocationListener(this, mapCoverage,
				getApplicationContext(), tm, strengthListener);
	}

	private void reloadFromDB() {
		CellHunterDbOpenHelper dbOpenHelper = new CellHunterDbOpenHelper(
				getApplicationContext());

		SQLiteDatabase database = dbOpenHelper.getWritableDatabase();

		Cursor cellCursor = database.query(
				CellHunterDbOpenHelper.GSM_CELL_TABLE_NAME, new String[] {
						"LAC", "CID", "NAME" }, null, null, null, null, null);

		while (cellCursor.getCount() > 0 && !cellCursor.isLast()) {
			cellCursor.moveToNext();

			int lac = cellCursor.getInt(0);
			int cid = cellCursor.getInt(1);
			String name = cellCursor.getString(2);

			Cell cell = new Cell(lac, cid, name);

			mapCoverage.putNewCellCoverage(cell);
		}

		cellCursor.close();

		Cursor sslCursor = database
				.query(CellHunterDbOpenHelper.SIGNAL_STRENGTH_LOCATION_TABLE_NAME,
						new String[] { "ID", "CELL_LAC", "CELL_CID",
								"LOCATION_LATITUDE", "LOCATION_LONGITUDE",
								"LOCATION_ACCURACY", "STRENGTH",
								"MESUREMENT_DATETIME" }, null, null, null,
						null, null);

		while (sslCursor.getCount() > 0 && !sslCursor.isLast()) {
			sslCursor.moveToNext();

			int lac = sslCursor.getInt(1);
			int cid = sslCursor.getInt(2);

			CellCoverage cellCoverage = mapCoverage.getCellCoverage(lac, cid);

			SignalStrengthLocation location = new SignalStrengthLocation();
			location.setId(sslCursor.getLong(0));
			location.setSignalStrengh(sslCursor.getInt(6));
			Location l = new Location(LocationManager.GPS_PROVIDER);
			l.setLatitude(sslCursor.getDouble(3));
			l.setLongitude(sslCursor.getDouble(4));
			l.setAccuracy(sslCursor.getFloat(5));
			location.setLocation(l);

			cellCoverage.getSignalStrenghLocations().add(location);
		}

		sslCursor.close();

		database.close(); // FIXME put in finally
	}

	@Override
	protected void onResume() {
		super.onResume();

		myLocationOverlay.enableCompass();
		myLocationOverlay.enableMyLocation();

		tm.listen(strengthListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
				0, myLocationListener);
	}

	@Override
	protected void onPause() {
		super.onPause();

		myLocationOverlay.disableCompass();
		myLocationOverlay.disableMyLocation();

		locationManager.removeUpdates(myLocationListener);
		tm.listen(strengthListener, PhoneStateListener.LISTEN_NONE);

		Toast.makeText(this, R.string.ui_remove_updates, Toast.LENGTH_SHORT)
				.show();
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {
		case R.id.viewStatistics:
			Bundle bundle = new Bundle();

			String stats = getStatistics();
			bundle.putString(ViewStatisticsActivity.TEXT, stats);

			Intent intent = new Intent(this, ViewStatisticsActivity.class);
			intent.putExtras(bundle);

			startActivity(intent);
			return true;
		case R.id.selectCell:
			Bundle bundle2 = new Bundle();

			String[] antennaList = getCellList();
			bundle2.putStringArray(CellSelectionActivity.CELL_LIST_KEY,
					antennaList);

			Intent intent2 = new Intent(this, CellSelectionActivity.class);
			intent2.putExtras(bundle2);

			startActivityForResult(intent2, SELECT_CELL_RESULTCODE);

			return true;

			// case R.id.editCell:
			// Bundle bundle3 = new Bundle();
			//
			// String[] cellList3 = getCellList();
			// bundle3.putStringArray(CellSelectionActivity.CELL_LIST_KEY,
			// cellList3);
			//
			// Intent intent3 = new Intent(this, CellSelectionActivity.class);
			// intent3.putExtras(bundle3);
			//
			// startActivityForResult(intent3, EDIT_CELL_RESULTCODE);
			//
			// return true;

		case R.id.emailDevelopper:
			Intent i = new Intent(Intent.ACTION_SEND);
			// i.setType("text/plain"); //use this line for testing in the
			// emulator
			i.setType("message/rfc822"); // use from live device
			i.putExtra(Intent.EXTRA_EMAIL,
					new String[] { "yves.dessertine2@gmail.com" });
			i.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_version));
			i.putExtra(Intent.EXTRA_TEXT, "Tell me about CellHunter");
			startActivity(Intent.createChooser(i, "Select email application."));

			return true;

		case R.id.helpAbout:
			String url = "http://code.google.com/p/cellhunter/wiki/Help";
			Intent intentHelpAbout = new Intent(Intent.ACTION_VIEW);
			intentHelpAbout.setData(Uri.parse(url));
			startActivity(intentHelpAbout);

			return true;

		case R.id.display_current_cell:
			CellLocation cellLocation = tm.getCellLocation();
			
			if (cellLocation == null) {
				Toast.makeText(this, R.string.ui_err_no_current_cell, Toast.LENGTH_SHORT).show();
				return true;
			}
			
			if (!(cellLocation instanceof GsmCellLocation)) {
				Toast.makeText(this, R.string.ui_err_cell_not_gsm, Toast.LENGTH_SHORT).show();
				return true;
			}
			
			GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
			// GLOBAL FIXME handle CDMA

			int lac = 0xffff & gsmCellLocation.getLac();
			int cid = 0xffff & gsmCellLocation.getCid();

			if (mapCoverage.isCellKnown(lac, cid)) {

				currentLac = lac;
				currentCid = cid;

				itemizedOverlay.updateMap(mapCoverage.getCellCoverage(
						currentLac, currentCid).getSignalStrenghLocations());
				if (!itemizedOverlayAlreadyAdded) {
					itemizedOverlayAlreadyAdded = true;
					overlays.add(itemizedOverlay);
				}
			} else
				Toast.makeText(getApplicationContext(),
						R.string.ui_currentNoMeasurements, Toast.LENGTH_SHORT)
						.show();

			return true;

		case R.id.deleteCell:

			Bundle bundleDeleteCell = new Bundle();

			String[] cellListDeleteCell = getCellList();
			bundleDeleteCell.putStringArray(
					CellSelectionActivity.CELL_LIST_KEY, cellListDeleteCell);

			Intent intentDeleteCell = new Intent(this,
					CellSelectionActivity.class);
			intentDeleteCell.putExtras(bundleDeleteCell);

			startActivityForResult(intentDeleteCell, DELETE_CELL_RESULTCODE);

			return true;
		case R.id.exportToSdcard:
			
			exportToSdcard();
			
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void exportToSdcard() {
		
		boolean mExternalStorageAvailable = false;
		boolean mExternalStorageWriteable = false;
		String state = Environment.getExternalStorageState();

		if (Environment.MEDIA_MOUNTED.equals(state)) {
		    // We can read and write the media
		    mExternalStorageAvailable = mExternalStorageWriteable = true;
		} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
		    // We can only read the media
		    mExternalStorageAvailable = true;
		    mExternalStorageWriteable = false;
		} else {
		    // Something else is wrong. It may be one of many other states, but all we need
		    //  to know is we can neither read nor write
		    mExternalStorageAvailable = mExternalStorageWriteable = false;
		}
		
		if(!(mExternalStorageAvailable && mExternalStorageWriteable)) {
			Toast.makeText(this, R.string.ui_sdcard_must_be_writable, Toast.LENGTH_SHORT).show();
			return;
		}
		
		File extdir = Environment.getExternalStorageDirectory();
		
		String extPath = extdir.getAbsolutePath();
		
		extPath = extPath + File.separator + "net.yvesd.cellhunter";
		
		String fileName = CellHunterDbOpenHelper.getDbName();
		
		Toast.makeText(this, "Saving file to: " + extPath + File.separator + fileName, Toast.LENGTH_LONG).show();
		
		File sr = new File("/data/data/net.yvesd.cellhunter/databases", fileName);
		File dt = new File(extPath, fileName);
		
		dt.getParentFile().mkdirs();
		
		String result = CopyFile.copyfile(sr, dt);
		
		Toast.makeText(this, result, Toast.LENGTH_LONG).show();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch (requestCode) {
		case SELECT_CELL_RESULTCODE:
			if (resultCode != RESULT_OK)
				break;

			String sel = data
					.getStringExtra(CellSelectionActivity.SELECTED_CELL_KEY);
			Toast.makeText(this, "Selected: " + sel, Toast.LENGTH_SHORT).show();

			// FIXME piggy : don't parse the String!
			String[] s = sel.split("/");
			int lac = Integer.valueOf(s[1]);
			int cid = Integer.valueOf(s[2]);

			currentLac = lac;
			currentCid = cid;

			CellCoverage acoverage = mapCoverage.getCellCoverage(lac, cid);
			if (acoverage == null) {
				Toast.makeText(this, R.string.ui_no_known_position,
						Toast.LENGTH_SHORT).show();
				break;
			} else {

				Set<SignalStrengthLocation> signalStrenghLocations = acoverage
						.getSignalStrenghLocations();
				itemizedOverlay.updateMap(signalStrenghLocations);
				if (!itemizedOverlayAlreadyAdded) {
					itemizedOverlayAlreadyAdded = true;
					overlays.add(itemizedOverlay);
				}
			}
			break;

		case EDIT_CELL_RESULTCODE:

			if (resultCode != RESULT_OK)
				break;

			Bundle bundle = new Bundle();

			String sel2 = data
					.getStringExtra(CellSelectionActivity.SELECTED_CELL_KEY);

			// FIXME piggy : don't parse the String!
			String[] s2 = sel2.split("/");
			String name2 = s2[0];
			int lac2 = Integer.valueOf(s2[1]);
			int cid2 = Integer.valueOf(s2[2]);

			bundle.putInt("LAC", lac2);
			bundle.putInt("CID", cid2);
			bundle.putString("NAME", name2);

			Toast.makeText(this, "Selected cid for edit : " + cid2,
					Toast.LENGTH_SHORT).show();

			showDialog(DIALOG_EDIT_CELL);

			break;

		case DELETE_CELL_RESULTCODE:

			if (resultCode != RESULT_OK)
				break;

			String selectionDeleteCell = data
					.getStringExtra(CellSelectionActivity.SELECTED_CELL_KEY);
			Toast.makeText(this,
					"Selected for deletation: " + selectionDeleteCell,
					Toast.LENGTH_SHORT).show();

			// FIXME piggy : don't parse the String!
			String[] sDeletation = selectionDeleteCell.split("/");
			int lacToDelete = Integer.valueOf(sDeletation[1]);
			int cidToDelete = Integer.valueOf(sDeletation[2]);

			mapCoverage.deleteCell(lacToDelete, cidToDelete);

			break;

		default:
			break;
		}
	}

	private String[] getCellList() {
		String[] list = new String[mapCoverage.getKnownCellsCount()];

		int i = 0;
		for (Cell c : mapCoverage.getCells()) {
			list[i] = c.getName() + "/" + c.getLac() + "/" + c.getCid();
			i++;
		}

		return list;
	}

	private String getStatistics() {

		Map<Cell, Integer> statistics = mapCoverage.getStatistics();

		StringBuffer buffer = new StringBuffer();

		buffer.append(getString(R.string.ui_stats_cells_known,
				statistics.size()));

		buffer.append("\n");

		int nbTotalMeasurements = 0;
		for (Map.Entry<Cell, Integer> e : statistics.entrySet())
			nbTotalMeasurements += e.getValue();
		buffer.append(getString(R.string.ui_stats_number_of_measurements,
				nbTotalMeasurements));

		buffer.append("\n");

		buffer.append("\n");

		buffer.append(getString(R.string.ui_stats_cells_list_header));

		for (Map.Entry<Cell, Integer> e : statistics.entrySet()) {

			buffer.append("\n  ");

			Cell cell = e.getKey();
			String name = cell.getName();
			int numberOfMesurements = e.getValue();

			buffer.append(getString(R.string.ui_stats_cells_list_line, name,
					cell.getLac(), cell.getCid(), numberOfMesurements));
		}

		return buffer.toString();
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog;
		switch (id) {
		case DIALOG_EDIT_CELL:
			dialog = new Dialog(getApplicationContext());

			dialog.setContentView(R.layout.enter_new_cellname_dialog);
			dialog.setTitle("Custom Dialog");

			TextView text = (TextView) dialog
					.findViewById(R.id.enterNewCellnameTextview);
			text.setText("Hello, this is a custom dialog!");
			break;
		default:
			dialog = null;
		}
		return dialog;
	}
}
